package com.wjk.cms.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.wjk.cms.service.WxGzhService;
import com.wjk.cms.util.wx.WxApiUtil;
import com.wjk.cms.util.wx.WxConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class WxGzhServiceImpl implements WxGzhService {

    final static String REDIS_KEY_PREFIX = "wx:xcx:scm:";

    final static String ACCESS_TOKEN_REDIS_KEY_SUFFIX = ":access_token";

    final static String JS_API_TICKET_REDIS_KEY_SUFFIX = ":js_api_ticket";

    final static int EXPIRATION_OFFSET = 120; // 缓存access_token的时候，少缓存一段时间，降低其过期的概率

    @Autowired
    private StringRedisTemplate redisTemplate;

    // Ideally, this should be synchronized at tenant+appid level, instead of globally.
    // It's only used for kxb wx xcx for xclm tenant.
    // Or, we can create a background thread to refresh the access token.
    @Override
    public synchronized String getAccessToken() {
        // get accessToken from Redis
        String redisKey = REDIS_KEY_PREFIX + WxConfig.GZH_APP_ID() + ACCESS_TOKEN_REDIS_KEY_SUFFIX;
        String accessToken = redisTemplate.opsForValue().get(redisKey);
        // if it's empty then ask a new one from wx and save it to redis and the accessToken local var
        int expiresIn = 0;
        if (StringUtils.isEmpty(accessToken)) {
            try {
                JSONObject newAccessTokenResp = doGetAccessToken(WxConfig.GZH_APP_ID(), WxConfig.GZH_APP_SECRET());
                accessToken = newAccessTokenResp.getString("access_token");
                expiresIn = newAccessTokenResp.getInteger("expires_in");
                expiresIn -= EXPIRATION_OFFSET;
                expiresIn = expiresIn < 0 ? 0 : expiresIn;
                redisTemplate.opsForValue().set(redisKey, accessToken, expiresIn, TimeUnit.SECONDS);
            } catch (Exception e) {
                log.error("获取微信公众号access_token失败 - " + e.getMessage(), e);
            }
        }
        // return the accessToken
        return accessToken;
    }

    @Override
    public synchronized void forceRefreshAccessToken() {
        String redisKey = REDIS_KEY_PREFIX + WxConfig.GZH_APP_ID() + ACCESS_TOKEN_REDIS_KEY_SUFFIX;
        String accessToken = null;
        int expiresIn = 0;
        try {
            JSONObject newAccessTokenResp = doGetAccessToken(WxConfig.GZH_APP_ID(), WxConfig.GZH_APP_SECRET());
            accessToken = newAccessTokenResp.getString("access_token");
            expiresIn = newAccessTokenResp.getInteger("expires_in");
            expiresIn -= EXPIRATION_OFFSET;
            expiresIn = expiresIn < 0 ? 0 : expiresIn;
            redisTemplate.opsForValue().set(redisKey, accessToken, expiresIn, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("获取微信公众号access_token失败 - " + e.getMessage(), e);
        }
    }

    @Override
    public synchronized String getJsApiTicket() {
        String accessToken = getAccessToken();
        // get jsApiTicket from Redis
        String redisKey = REDIS_KEY_PREFIX + WxConfig.GZH_APP_ID() + JS_API_TICKET_REDIS_KEY_SUFFIX;
        String jsApiTicket = redisTemplate.opsForValue().get(redisKey);
        // if it's empty then ask a new one from wx and save it to redis and the jsApiTicket local var
        int expiresIn = 0;
        if (StringUtils.isEmpty(jsApiTicket)) {
            try {
                JSONObject resp = doGetJsApiTicket(accessToken);
                jsApiTicket = resp.getString("ticket");
                expiresIn = resp.getInteger("expires_in");
                expiresIn -= EXPIRATION_OFFSET;
                expiresIn = expiresIn < 0 ? 0 : expiresIn;
                redisTemplate.opsForValue().set(redisKey, jsApiTicket, expiresIn, TimeUnit.SECONDS);
            } catch (Exception e) {
                log.error("获取微信公众号access_token失败 - " + e.getMessage(), e);
            }
        }
        // return the jsApiTicket
        return jsApiTicket;
    }

    /**
     * 获取公众号全局唯一后台接口调用凭据（access_token）。
     * <p>
     * auth.getAccessToken
     * <p>
     * GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
     */
    static JSONObject doGetAccessToken(String appid, String secret) throws Exception {
        return WxApiUtil.get("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret);
    }

    static JSONObject doGetJsApiTicket(String accessToken) throws Exception {
        return WxApiUtil.get("https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=" + accessToken);
    }

}
